【忍者算法】Google搜索框背后的算法:带你深入理解前缀树|LeetCode 208 实现Trie(前缀树)
你有没有好奇过,当你在搜索框输入时,为什么能瞬间给出相关的搜索建议?今天,让我们揭开这个神奇功能背后的数据结构:Trie(前缀树)。
🌟 生活中的前缀树
想象你在整理一本英语词典:
- 所有以'a'开头的词放在A章节
- 在A章节中,再按第二个字母分类
- 以此类推...
这种层层递进的组织方式,就是前缀树的思想!
💡 前缀树是什么?
Trie(读作"try"或"tree")是一种树形数据结构:
- 每个节点代表一个字符
- 从根节点到某个节点的路径表示一个字符串
- 特别适合用来存储和查找字符串集合
🎨 可视化理解
假设我们要存储这些单词:
root
|
c
|
a
/ \
t r
|
d看到了吗?这就像一个字符串的"家谱树"!
⚡ 完整代码实现
java
class Trie {
private class TrieNode {
private TrieNode[] children; // 子节点数组
private boolean isEnd; // 标记是否是单词结尾
public TrieNode() {
children = new TrieNode[26]; // 26个小写字母
isEnd = false;
}
}
private TrieNode root; // 根节点
public Trie() {
root = new TrieNode();
}
// 插入单词
public void insert(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
int index = c - 'a'; // 获取字符对应的索引
if (node.children[index] == null) {
node.children[index] = new TrieNode();
}
node = node.children[index];
}
node.isEnd = true; // 标记单词结尾
}
// 查找单词
public boolean search(String word) {
TrieNode node = searchPrefix(word);
return node != null && node.isEnd; // 必须完整匹配且是单词结尾
}
// 查找前缀
public boolean startsWith(String prefix) {
return searchPrefix(prefix) != null; // 只需要前缀匹配
}
// 查找公共方法
private TrieNode searchPrefix(String prefix) {
TrieNode node = root;
for (char c : prefix.toCharArray()) {
int index = c - 'a';
if (node.children[index] == null) {
return null; // 中途找不到,直接返回null
}
node = node.children[index];
}
return node;
}
}🎬 模拟运行过程
让我们一步步看看如何构建一个前缀树:
1. 初始状态:
root
2. 插入"cat":
root
|
c
|
a
|
t* (* 表示单词结尾)
3. 插入"car":
root
|
c
|
a
/ \
t* r*
4. 再插入"card":
root
|
c
|
a
/ \
t* r*
|
d*🔍 核心操作解析
1. 插入操作
就像在建立一个文件目录:
- 沿着已有的路径走
- 如果没路了,就新建路径
- 最后标记一下这是个完整的词
2. 查找操作
像是在玩寻宝游戏:
- 顺着路径一直走
- 中途断了就返回false
- 找到了还要检查是否是完整的词
3. 前缀查找
和普通查找类似,但更宽松:
- 不需要走到尽头
- 只要能找到这段路径就行
📊 复杂度分析
时间复杂度:
- 插入:O(m),m是单词长度
- 查找:O(m)
- 前缀查找:O(m)
空间复杂度:
- O(TOTAL),TOTAL是所有单词字符数的总和
🎯 实战应用场景
- 搜索引擎的自动补全
- 拼写检查器
- IP地址路由表
- 文件系统的路径管理
💡 性能优化技巧
- 压缩前缀树:合并单一路径的节点
优化前: 优化后:
c ca
| → |
a t
|
t- 使用HashMap代替数组:
java
private Map<Character, TrieNode> children; // 更灵活,支持更多字符🎁 思考题
如何修改代码实现以下功能:
- 统计某个前缀出现的次数?
- 支持删除操作?
- 查找最长公共前缀?
如果你知道答案,或者有自己的想法?欢迎在评论区留言、讨论~
📝 代码模板总结
实现Trie时的核心要点:
- 定义节点结构(children数组 + 结束标记)
- 实现三个基本操作(插入、查找、前缀查找)
- 抽取公共查找逻辑
- 注意字符索引转换
作者:忍者算法
公众号:忍者算法
🎯 回复【刷题清单】获取更多经典题目解析 👥 回复【加群】加入算法/面试交流群,一起学习进步 🧑💻 回复【代码】获取GitHub完整题解项目,包含Java/Python/JavaScript/Go/C++多语言实现
#算法面试 #LeetCode #数据结构 #前缀树